﻿using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Microsoft.IdentityModel.Claims;
using Veracruz.IdentityModel;
using Microsoft.IdentityModel.Web;
using Veracruz.Facebook.IdentityModel;
using System.Globalization;
using System.Threading;

namespace Veracruz.Facebook.Web.Security
{
    public class FacebookMembershipProvider : MembershipProvider
    {
        #region fields

        private string m_applicationName;

        #endregion
        #region props

        public override string ApplicationName
        {
            get { return m_applicationName; }
            set { m_applicationName = value; }
        }
        public override bool EnablePasswordReset
        {
            get { throw new NotImplementedException(); } // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }
        public override bool EnablePasswordRetrieval
        {
            get { throw new NotImplementedException(); } // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }
        public override int MaxInvalidPasswordAttempts
        {
            get { throw new NotImplementedException(); } // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }
        public override int MinRequiredNonAlphanumericCharacters
        {
            get { throw new NotImplementedException(); } // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }

        public override int MinRequiredPasswordLength
        {
            get { throw new NotImplementedException(); } // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }

        public override int PasswordAttemptWindow
        {
            get { throw new NotImplementedException(); } // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { throw new NotImplementedException(); } // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }

        public override string PasswordStrengthRegularExpression
        {
            get { throw new NotImplementedException(); } // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { throw new NotImplementedException(); } // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }

        public override bool RequiresUniqueEmail
        {
            get { throw new NotImplementedException(); } // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }

        #endregion
        #region not implemented methods

        private Session GetSession()
        {
            IClaimsIdentity l_identity = Thread.CurrentPrincipal.Identity as IClaimsIdentity;
            if (l_identity == null)
            {
                throw new NotSupportedException();
            }

            Session l_session = null;
            if (String.Compare(l_identity.AuthenticationType, "Facebook", true, CultureInfo.InvariantCulture) == 0)
            {
                l_session = l_identity.GetSession();
            }
            else
            {
                ClaimsPrincipal __facebookPrincipal = HttpContext.Current.Session["CachedClaims"] as ClaimsPrincipal;
                if (__facebookPrincipal != null)
                {
                    l_session = ((IClaimsIdentity)__facebookPrincipal.Identity).GetSession();
                }
                else 
                {
                    HttpContext.Current.Response.Redirect("~/_admin/facebookauth.aspx");
                }
            }

            if (l_session == null)
            {
                throw new NotSupportedException();
            }
            return l_session;
        }
        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            throw new NotImplementedException(); // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }
        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new NotImplementedException(); // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }
        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            throw new NotImplementedException(); // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }
        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            throw new NotImplementedException(); // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }
        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException(); // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }
        public override string ResetPassword(string username, string answer)
        {
            throw new NotImplementedException(); // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }
        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException(); // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }
        public override void UpdateUser(MembershipUser user)
        {
            throw new NotImplementedException(); // HACK : This membership provider is only a facade of the Facebook authentication mechanim.
        }

        #endregion
        #region methods

        public override string GetUserNameByEmail(string email)
        {
            return email; // The username is equals to the email.
        }
        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            UserInfo[] l_userInfos = FacebookHelper.GetAllUserInfos(GetSession(), pageIndex, pageSize);
            totalRecords = l_userInfos.Length;
            MembershipUserCollection l_membershipUserCollection = new MembershipUserCollection();
            for (int i = 0; i < l_userInfos.Length; i++)
            {
                l_membershipUserCollection.Add(l_userInfos[i].CreateMembershipUser());
            }
            return l_membershipUserCollection;
        }
        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            if (string.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }
            UserInfo l_userInfo = FacebookHelper.GetUserInfo(GetSession(), username);
            if (l_userInfo == null)
                return null;
            else
                return l_userInfo.CreateMembershipUser();
        }
        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            if (!(providerUserKey is long))
            {
                throw new NotImplementedException();
            }
            UserInfo l_userInfo = FacebookHelper.GetUserInfo(GetSession(), (long)providerUserKey);
            return l_userInfo.CreateMembershipUser();
        }
        public override bool ValidateUser(string username, string password)
        {
            //if (!string.IsNullOrEmpty(password))
            //{
            //    throw new ArgumentException("", "password");
            //}
            //IClaimsIdentity l_identity = (IClaimsIdentity)ClaimsPrincipal.Current.Identity;
            //string l_email = l_identity.GetClaimValue(System.IdentityModel.Claims.ClaimTypes.Email);
            //return (l_email == username);
            
            IClaimsIdentity __claimsIdentity = Thread.CurrentPrincipal.Identity as IClaimsIdentity;
            return __claimsIdentity != null && __claimsIdentity.IsAuthenticated;
        }
        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            if (string.IsNullOrEmpty(usernameToMatch))
            {
                throw new ArgumentNullException("usernameToMatch");
            }

            UserInfo[] l_userInfos = FacebookHelper.FindUserInfosByFullName(GetSession(), usernameToMatch, pageIndex, pageSize);
            totalRecords = l_userInfos.Length;

            MembershipUserCollection l_membershipUserCollection = new MembershipUserCollection();
            for (int i = 0; i < l_userInfos.Length; i++)
            {
                l_membershipUserCollection.Add(l_userInfos[i].CreateMembershipUser());
            }
            return l_membershipUserCollection;
            //return this.FindUsersByEmail(usernameToMatch, pageIndex, pageSize, out totalRecords);
        }
        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            if (string.IsNullOrEmpty(emailToMatch))
            {
                throw new ArgumentNullException("emailToMatch");
            }
            UserInfo[] l_userInfos = FacebookHelper.FindUserInfosByEmail(GetSession(), emailToMatch, pageIndex, pageSize);
            totalRecords = l_userInfos.Length;
            MembershipUserCollection l_membershipUserCollection = new MembershipUserCollection();
            for (int i = 0; i < l_userInfos.Length; i++)
            {
                l_membershipUserCollection.Add(l_userInfos[i].CreateMembershipUser());
            }
            return l_membershipUserCollection;
        }
        public override int GetNumberOfUsersOnline()
        {
            // HACK : Facebook provides currently a who is online feature only on friends of an user.
            // TODO : Develop a online mechanism on dedicated association facebook data store ?
            return FacebookHelper.GetNumberOfUsersOnline(GetSession());
        }

        #endregion
    }
}
